package com.gitee.wsl.text.reader.line

class PositionRange internal constructor(val start: LookaheadText.Position,
                                         val end: LookaheadText.Position
): Comparable<PositionRange> {

    val isFlat: Boolean
        get() = start == end

    fun isEmpty(): Boolean = start == end

    override fun compareTo(other: PositionRange): Int {
        val cmp = this.start.compareTo(other.start)
        return if (cmp == 0) {
            this.end.compareTo(other.end)
        } else {
            cmp
        }
    }

    /**
     * Tests whether the given point is contained in the interval represented by this object.
     * @param point the point.
     */
    fun contains(point: LookaheadText.Position): Boolean =
        ((point == start || start.isBefore(point)) && (point == end || point.isBefore(end)))

    /**
     * Tests whether the given range is contained in the interval represented by this object.
     * @param positionRange the range
     */
    fun contains(positionRange: PositionRange?): Boolean =
        (positionRange != null) &&
                this.start.isSameOrBefore(positionRange.start) &&
                this.end.isSameOrAfter(positionRange.end)

    /**
     * Tests whether the given range overlaps the interval represented by this object.
     * @param positionRange the range
     */
    fun overlaps(positionRange: PositionRange?): Boolean =
        (positionRange != null) && (
                (this.start.isSameOrAfter(positionRange.start) && this.start.isSameOrBefore(positionRange.end)) ||
                        (this.end.isSameOrAfter(positionRange.start) && this.end.isSameOrBefore(positionRange.end)) ||
                        (positionRange.start.isSameOrAfter(this.start) && positionRange.start.isSameOrBefore(this.end)) ||
                        (positionRange.end.isSameOrAfter(this.start) && positionRange.end.isSameOrBefore(this.end))
                )

    /**
     * Extends the range so it includes also all remaining characters in the last line including the line break
     */
    fun toTheLineEndWithLineBreak(): PositionRange = PositionRange(start, end.nextLinePosition()!!)
}

fun LookaheadText.Position.fromPositionTillLineEnd( ) = PositionRange(this, this.lineEndPosition())

fun LookaheadText.Position.fromLineStartTillPosition() = PositionRange(this.lineStartPosition(), this)

fun LookaheadText.Position.fullLine()= PositionRange(lineStartPosition(), lineEndPosition())